import { createAxios } from './axios'
import type { HttpConfigType, ApiObject, Method, ExConfigParams } from '@/service/http-type'
import { httpDefaultConfig } from '@/service/http-type'
import { Cache } from '@/storage'
import { CacheKey } from "@/storage/mutation-type"
import { useAppStore } from '@/stores'
import type { AxiosResponse, AxiosError } from 'axios'
import { dealConfigs } from "@/service/dealConfigs"
import { isObject, isString, isFunction } from '@/service/type-utils'
import { downloadFile } from "@/service/helper"
import { cloneDeep } from 'lodash-es'

let basicHttOption: HttpConfigType

export class http {
  static fetch(urlOrApiObject: string | ApiObject, params?: object, method?: Method, exparams?: Partial<ExConfigParams>): Promise<any> {
    const { getAxiosInstance } = useAppStore()

    let { config, afterResponse } = dealConfigs(urlOrApiObject, params, method, exparams)

    return new Promise((resolve, reject) => {
      getAxiosInstance.request(config).then((res: AxiosResponse) => {
        const { onlyData = true, okCode = basicHttOption?.okCode as number | 200 } = (isObject(urlOrApiObject) ? (urlOrApiObject as ApiObject)?.exparams??exparams??{} : exparams??{}) as Partial<ExConfigParams>
        let rsp
        if(onlyData && res['code'] === okCode) {
          rsp = res.data??{}
        }else {
          rsp = res
        }

        if(afterResponse) {
          afterResponse(rsp)
        }

        // afterFetch,接口请求后的钩子
        if(isObject(urlOrApiObject)) {
          const { afterFetch } = urlOrApiObject
          if( afterFetch && isFunction(afterFetch) ) {
            let result = afterFetch( rsp )
            if( result ) rsp = { ...result }
          }
        }

        resolve(rsp)
      }).catch((err: Error | AxiosError) => {
        reject(err)
      })
    })
  }

  static post(urlOrApiObject: string | ApiObject, params?: object, exparams?: Partial<ExConfigParams>): Promise<any> {
    return this.fetch(urlOrApiObject, params, 'post', exparams)
  }

  static get(urlOrApiObject: string | ApiObject, params?: object, exparams?: Partial<ExConfigParams>): Promise<any> {
    return this.fetch(urlOrApiObject, params, 'get', exparams)
  }

  static put(urlOrApiObject: string | ApiObject, params?: object, exparams?: Partial<ExConfigParams>): Promise<any> {
    return this.fetch(urlOrApiObject, params, 'put', exparams)
  }

  static delete(urlOrApiObject: string | ApiObject, params?: object, exparams?: Partial<ExConfigParams>): Promise<any> {
    return this.fetch(urlOrApiObject, params, 'delete', exparams)
  }

  static patch(urlOrApiObject: string | ApiObject, params?: object, exparams?: Partial<ExConfigParams>): Promise<any> {
    return this.fetch(urlOrApiObject, params, 'patch', exparams)
  }

  static exportFile(urlOrApiObject: string | ApiObject, params?: object, fileName: string = '') {
    let config: ApiObject = {
      url: ''
    }
    if(isString(urlOrApiObject)) {
      config['responseType'] = 'blob'
      config['url'] = urlOrApiObject
    }else {
      config = { responseType: 'blob', ...urlOrApiObject }
    }
    this.fetch(config, params, 'post').then(res => {
      let name
      if(basicHttOption.ReturnResData) {
        name = decodeURI(res.headers['content-disposition'].split(';')[1].split('filename=')[1])
      }else {
        name = fileName
      }
      downloadFile(res?.data, name)
    })
  }

  static uploadFile(urlOrApiObject: string | ApiObject, params?: object, exparams?: Partial<ExConfigParams>): Promise<any> {
    return this.fetch(urlOrApiObject, params, 'post', { isFormData: true, onlyData: false, ...exparams})
  }

}

export function initHttp(options: HttpConfigType) {
  basicHttOption = cloneDeep(options)
  let baseConfig = {}

  if(options?.TokenKey) {
    let token = Cache.getLocal(CacheKey.TOKEN)
    if( token ) {
      baseConfig['headers'] = options?.Headers || {}
      baseConfig['headers'][options?.TokenPreKey || httpDefaultConfig.tokenPreKey] = options?.TokenPreKey || '' + token
    }
  }

  baseConfig['baseURL'] = options?.BaseURL || ''
  baseConfig['method'] = options?.Method || httpDefaultConfig.defaultMethod
  baseConfig['ReturnResData'] = options?.ReturnResData || httpDefaultConfig.returnResData
  options?.Timeout ? baseConfig['timeout'] = options.Timeout : ''
  options?.dealResponseError ? baseConfig['dealResponseError'] = options.dealResponseError : ''
  options?.dealRequest ? baseConfig['dealRequest'] = options.dealRequest : ''
  options?.dealResponse ? baseConfig['dealResponse'] = options.dealResponse : ''

  createAxios(baseConfig)
}
